﻿using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace SObject.Test
{
    [TestFixture]
    class Serializer
    {
        [Test, TestCaseSource("testCaseSource_LoadFromFile")]
        public void LoadFromFile(LoadFromFileTestModel Model)
        {
            SObject.Object obj = LoadObject(Model.Filename, Model.CheckObjectName);
            VerifySimilar(obj, Model.CompareSource);
        }

        [Test]
        [TestCase("estObject.object.xml", "TestObject", ExpectedException = typeof(SObject.Exception))]
        public void LoadFromFile_WithNameMismatch(string Filename, string CheckObjectName)
        {
            SObject.Object obj = LoadObject(Filename, CheckObjectName);
        }

        private SObject.Object LoadObject(string Filename, string CheckObjectName)
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            var assemblyName = assembly.GetName();
            Stream file = assembly.GetManifestResourceStream(assemblyName.Name + ".Resources." + Filename);

            SObject.Serializer serializer = new SObject.Serializer();
            SObject.Object obj = serializer.LoadFromFile(file, CheckObjectName);

            return (obj);
        }

        private void VerifySimilar(SObject.Object First, SObject.Object Second)
        {
            Assert.That(First.Name, Is.EqualTo(Second.Name));
            Assert.That(First.ValueCount, Is.EqualTo(Second.ValueCount));

            IEnumerable<string> loadedValues = First.Values;
            IEnumerable<string> caseValues = Second.Values;

            var values = loadedValues.Zip(caseValues, (x, y) => new { X = x, Y = y });
            foreach (var valuePair in values)
            {
                Assert.That(valuePair.X, Is.EqualTo(valuePair.Y));
            }

            var childrenPair = First.GetChildren().Zip(Second.GetChildren(), (x, y) => new { X = x, Y = y });
            foreach (var childPair in childrenPair)
            {
                VerifySimilar(childPair.X, childPair.Y);
            }
        }

        public class LoadFromFileTestModel
        {
            public string Filename { get; set; }
            public string CheckObjectName { get; set; }
            public SObject.Object CompareSource { get; set; }
        }

        private static IEnumerable<LoadFromFileTestModel> testCaseSource_LoadFromFile
        {
            get
            {
                SObject.Object obj = new SObject.Object("TestObject");
                obj.AddValue("First value");
                obj.AddValue("Second value");
                yield return new LoadFromFileTestModel() { Filename = "TestObject.object.xml", CheckObjectName = "TestObject", CompareSource = obj };

                obj = new SObject.Object("testObject2");
                obj.AddValue("First value");
                obj.AddValue("Second value");
                var childObject = new SObject.Object("ChildObject");
                childObject.AddValue("3");
                obj.AddChild(childObject);
                yield return new LoadFromFileTestModel() { Filename = "testObject2.object.xml", CheckObjectName = "testObject2", CompareSource = obj };
            }
        }
    }
}
